package options;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore.Entry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

//import com.sun.xml.tree.XmlDocument;

import demo.cypher.FileEncrypter;

public class AppSettings {
	private static HashMap<String,List<HashMap>> hashMap;
	private HashMap fHashMap;
	private static AppSettings SINGLETON;
	private AppSettings() {
	    fHashMap = new HashMap();
	    hashMap=new HashMap<String,List<HashMap>>();
	  }
	
	
	
	public static HashMap<String, List<HashMap>> getHashMap() {
		return hashMap;
	}



	public static Object get(String key) {
	    return SINGLETON.fHashMap.get(key);
	}
	
	public static Object get(String key, String attributeKey) {
		List<HashMap> hashMaps=SINGLETON.hashMap.get(key);
		for(HashMap<String, String> hashMap:hashMaps){
			if(hashMap.containsKey(attributeKey)){
				return hashMap.get(attributeKey);
			}
			
		}
		return null;
	}
	
	public static Object get(String key, String attributeKey, Object deflt) {
		List<HashMap> hashMaps=SINGLETON.hashMap.get(key);
		if(hashMaps==null){
			return deflt;
		}
		for(HashMap<String, String> hashMap:hashMaps){
			if(hashMap.containsKey(attributeKey)){
				return hashMap.get(attributeKey);
			}
			
		}
		return null;
	}


	  public static Object get(String key, Object deflt) {
	    Object obj = SINGLETON.fHashMap.get(key);
	    if (obj == null) {
	      return deflt;
	    } else {
	      return obj;
	    }
	  }


	  public static int getInt(String key, int deflt) {
	    Object obj = SINGLETON.fHashMap.get(key);
	    if (obj == null) {
	      return deflt;
	    } else {
	      return new Integer((String) obj).intValue();
	    }
	  }
	  
	  public static void clear() {
		    SINGLETON.fHashMap.clear();
	  }
	  
	  public static void put(String key, Object data) {
		    //prevent null values. Hasmap allow them
		    if (data == null) {
		      throw new IllegalArgumentException();
		    } else {
		      SINGLETON.fHashMap.put(key, data);
		    }
	  }
	  
	  public static void put(String key, List<HashMap> data) {
		    //prevent null values. Hasmap allow them
		    if (data == null) {
		      throw new IllegalArgumentException();
		    } else {
		      SINGLETON.hashMap.put(key, data);
		    }
	  }
	  
		/**
		 * Возвращает объект Document, который является объектным представлением
		 * XML документа.
		 */
		private static Document getDocument(InputStream inputStream) throws Exception {
			try {
				DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
				f.setValidating(false);
				DocumentBuilder builder = f.newDocumentBuilder();
//				return builder.parse(inn);
//				return builder.parse(new File("H:/Projects/JavaProjects/eclipseProjects/staffList/src/options/staffConfigDec.xml"));
				InputSource isrc = new InputSource(inputStream);
				isrc.setEncoding("utf8");
//				System.out.println("isrc.getEncoding(): "+isrc.getEncoding());
				return builder.parse(isrc);
			} catch (Exception exception) {
				System.out.println("exception : "+exception.getMessage());
				exception.printStackTrace();
			}
			return null;
		}
		
	  public static InputStream getInputStreamEn(){
		 try {
			 String keyPhase = "javasun";
			 FileEncrypter fe = new FileEncrypter(keyPhase);
//			 return fe.getDecryptInputStreamReader(new FileInputStream("src/options/staffConfigEn"));
//			 return fe.getDecryptInputStreamReader(new FileInputStream("src/demo/xml/staffConfigEn"));
			 String path = AppSettings.class.getProtectionDomain().getCodeSource().getLocation().getPath();
			 System.out.println("path: "+path+"staffConfigEn");
			 return fe.getDecryptInputStreamReader(new FileInputStream(path+"staffConfigEn"));
//			 AppSettings.class.getResource("staffConfigEn");
//			 return fe.getDecryptInputStreamReader(AppSettings.class.getResourceAsStream("staffConfigEn"));
			 
		} catch (Exception e) {
			// TODO: handle exception
		}
		return null; 
	  }
	  
	  public static void load() throws Exception{
		  Document document=getDocument(getInputStreamEn());
		  if (document == null) {
		      throw new NullPointerException();
		  }
		  NodeList nodeList = document.getDocumentElement().getChildNodes();
		  if(nodeList!=null){
			 for(int i=0;i<nodeList.getLength();i++){
			   Node node=nodeList.item(i);
//			   System.out.println("node: "+i+" "+node.getNodeName());
			   NamedNodeMap attributes=node.getAttributes();
			   if(attributes!=null){
				   List<HashMap> hashMapList=new ArrayList<HashMap>();
//				  System.out.println("node: "+i+" "+node.getNodeName()); 
				  for(int k=0;k<attributes.getLength();k++){
					 HashMap<String, String> tempHashMap=new HashMap<String, String>();
					 tempHashMap.put(attributes.item(k).getNodeName(), attributes.item(k).getNodeValue());
					 hashMapList.add(tempHashMap);
//					 System.out.println("attributes: "+attributes.item(k).getNodeName());
//					 System.out.println("attributes values: "+attributes.item(k).getNodeValue()); 
				  }
				  put(node.getNodeName(), hashMapList);
			   }
		     } 
		  }
	  }
	  
	  public static boolean save(File file) throws Exception {
		  // Создаем новое DOM дерево
//		  DOMImplementation domImpl = new DOMImplementation();
//		  Document doc = domImpl.createDocument(null, "options", null);
		  Document document=getDocument(getInputStreamEn());
		  if (document == null) {
		      throw new NullPointerException();
		  }
		  Element root = document.getDocumentElement();
		  for(Map.Entry<String, List<HashMap>> hashMapList:AppSettings.getHashMap().entrySet()){
			root.appendChild(document.createElement(hashMapList.getKey()));  
		  }
		  
		  
		  
		  return true;
		}
	  
public static void saveConfig() throws Exception
	  {
//	   BufferedWriter writer = new BufferedWriter
//	    ( new OutputStreamWriter( new FileOutputStream( "src/demo/xml/staffConfigDe" ), "utf8") );

	   try
	     {
//	      XmlDocument xdoc = new XmlDocument();
		  DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
		  f.setValidating(false);
		  DocumentBuilder builder = f.newDocumentBuilder();
		  Document xdoc = builder.newDocument(); 
	      Element xroot = xdoc.createElement("options");
	      for(Map.Entry<String, List<HashMap>> hashMapList:AppSettings.getHashMap().entrySet()){
	    	  Element node=xdoc.createElement(hashMapList.getKey());
	    	  List<HashMap> attributesHashMapList=hashMapList.getValue();
	    	  for(HashMap<String, String> attributes:attributesHashMapList){
	    		  for(Map.Entry<String, String> entry:attributes.entrySet()){
//	    			Node attributeNode=xdoc.createElement(entry.getKey());
//	    			attributeNode.setNodeValue(entry.getValue());
//	    		    node.appendChild(attributeNode);
	    			  node.setAttribute(entry.getKey(), entry.getValue());
	    		  }
	    		  
	    	  }
//	    	  xroot.appendChild(xdoc.createElement(hashMapList.getKey()));
	    	  xroot.appendChild(node);
		  }

	      xdoc.appendChild(xroot);
//	      xdoc.write(writer, "utf8");
	      DOMSource source = new DOMSource(xdoc);
	      StringWriter xmlAsWriter = new StringWriter();
	      StreamResult result = new StreamResult(xmlAsWriter);
	      TransformerFactory.newInstance().newTransformer().transform(source, result);
	      StringReader xmlReader = new StringReader(xmlAsWriter.toString());
//	      InputSource viola = new InputSource(xmlReader);
	      ByteArrayInputStream inputStream = new ByteArrayInputStream(xmlAsWriter.toString().getBytes("UTF-8"));
	      String keyPhase = "javasun";
		  FileEncrypter fe = new FileEncrypter(keyPhase);
//		  fe.encrypt(inputStream, new FileOutputStream("src/demo/xml/staffConfigEn"));
		  String path = AppSettings.class.getProtectionDomain().getCodeSource().getLocation().getPath();
		  fe.encrypt(inputStream, new FileOutputStream(path+"staffConfigEn"));
	     }catch (Exception e) {
				System.out.println("error message: "+e.getMessage());
				e.printStackTrace();
			}
//	   finally { writer.close(); }
	  }
	  static {
		 SINGLETON = new AppSettings();
	  }
	  
	  public static void createAppSettings(){
		  try {
				AppSettings.clear();
				AppSettings.load();
			} catch (Exception e) {
				System.out.println("error message: "+e.getMessage());
				e.printStackTrace();
			} 
	  }
	

}
